<html>
<head><meta charset="utf-8"><title>Better enums · project-error-handling · Zulip Chat Archive</title></head>
<h2>Stream: <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/index.html">project-error-handling</a></h2>
<h3>Topic: <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html">Better enums</a></h3>

<hr>

<base href="https://rust-lang.zulipchat.com">

<head><link href="https://rust-lang.github.io/zulip_archive/style.css" rel="stylesheet"></head>

<a name="210592717"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210592717" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> alex <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210592717">(Sep 19 2020 at 02:22)</a>:</h4>
<p>Often, I'll see libraries that have many different errors that could be raised, they'll often place them inside of one single enum that every function returns. It would be nice if you could specify that a function returns only a subset of an enum</p>



<a name="210593215"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210593215" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> BatmanAoD (Kyle Strand) <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210593215">(Sep 19 2020 at 02:35)</a>:</h4>
<p>I think that would be especially useful if different functions return overlapping subsets of the set of possible errors, since that can't be modeled with nested enums.</p>



<a name="210599668"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210599668" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> XAMPPRocky <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210599668">(Sep 19 2020 at 06:04)</a>:</h4>
<p>I think large error enums are an anti-pattern overall as it requires people to handle error cases that could be impossible to trigger. In my opinion, error enums should be as small and isolated as much as possible.</p>
<p>That would also require a significant language changes and this is a libs team project group.</p>



<a name="210614641"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210614641" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Joshua Nelson <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210614641">(Sep 19 2020 at 13:15)</a>:</h4>
<blockquote>
<p>I think large error enums are an anti-pattern overall as it requires people to handle error cases that could be impossible to trigger.</p>
</blockquote>
<p>/me glares at <a href="https://docs.rs/toml/0.5.6/toml/ser/fn.to_string.html">https://docs.rs/toml/0.5.6/toml/ser/fn.to_string.html</a></p>



<a name="210614663"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210614663" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Joshua Nelson <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210614663">(Sep 19 2020 at 13:15)</a>:</h4>
<p>err ... actually I might have just misread that page, it looks like that's specific to serialization errors</p>



<a name="210615454"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210615454" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jake Goulding <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210615454">(Sep 19 2020 at 13:33)</a>:</h4>
<p>Right now, SNAFU encourages creating enums with some light recommendation to make <em>multiple</em> error types. One per module, for example, but also more. There's a ergonomic tradeoff between many variants that people have to handle vs many error types people have to handle.</p>
<p>I'm working on something like this for SNAFU at the moment:</p>
<div class="codehilite"><pre><span></span><code><span class="cp">#[derive(Debug, Snafu)]</span><span class="w"></span>
<span class="k">struct</span> <span class="nc">Error1</span><span class="p">;</span><span class="w"></span>
<span class="cp">#[derive(Debug, Snafu)]</span><span class="w"></span>
<span class="k">struct</span> <span class="nc">Error2</span><span class="p">;</span><span class="w"></span>
<span class="cp">#[derive(Debug, Snafu)]</span><span class="w"></span>
<span class="k">struct</span> <span class="nc">Error3</span><span class="p">;</span><span class="w"></span>

<span class="cp">#[derive(Debug, Snafu)]</span><span class="w"></span>
<span class="k">enum</span> <span class="nc">ErrorA</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">Error1</span><span class="p">(</span><span class="n">Error1</span><span class="p">),</span><span class="w"> </span><span class="n">Error2</span><span class="p">(</span><span class="n">Error2</span><span class="p">)</span><span class="w"> </span><span class="p">}</span><span class="w"></span>

<span class="cp">#[derive(Debug, Snafu)]</span><span class="w"></span>
<span class="k">enum</span> <span class="nc">ErrorB</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">Error3</span><span class="p">(</span><span class="n">Error3</span><span class="p">),</span><span class="w"> </span><span class="n">Error2</span><span class="p">(</span><span class="n">Error2</span><span class="p">)</span><span class="w"> </span><span class="p">}</span><span class="w"></span>

<span class="k">fn</span> <span class="nf">f1</span><span class="p">()</span><span class="w"> </span>-&gt; <span class="nb">Result</span><span class="o">&lt;</span><span class="p">(),</span><span class="w"> </span><span class="n">Error1</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{}</span><span class="w"></span>
<span class="k">fn</span> <span class="nf">f2</span><span class="p">()</span><span class="w"> </span>-&gt; <span class="nb">Result</span><span class="o">&lt;</span><span class="p">(),</span><span class="w"> </span><span class="n">Error2</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{}</span><span class="w"></span>
<span class="k">fn</span> <span class="nf">f3</span><span class="p">()</span><span class="w"> </span>-&gt; <span class="nb">Result</span><span class="o">&lt;</span><span class="p">(),</span><span class="w"> </span><span class="n">Error3</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{}</span><span class="w"></span>

<span class="k">fn</span> <span class="nf">fa</span><span class="p">()</span><span class="w"> </span>-&gt; <span class="nb">Result</span><span class="o">&lt;</span><span class="p">(),</span><span class="w"> </span><span class="n">ErrorA</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="n">f1</span><span class="p">()</span><span class="o">?</span><span class="p">;</span><span class="w"></span>
<span class="w">    </span><span class="n">f2</span><span class="p">()</span><span class="o">?</span><span class="p">;</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>

<span class="k">fn</span> <span class="nf">fb</span><span class="p">()</span><span class="w"> </span>-&gt; <span class="nb">Result</span><span class="o">&lt;</span><span class="p">(),</span><span class="w"> </span><span class="n">ErrorB</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="n">f3</span><span class="p">()</span><span class="o">?</span><span class="p">;</span><span class="w"></span>
<span class="w">    </span><span class="n">f2</span><span class="p">()</span><span class="o">?</span><span class="p">;</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>



<a name="210615515"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210615515" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jake Goulding <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210615515">(Sep 19 2020 at 13:34)</a>:</h4>
<p>I'll probably also need to figure out some way of going from subset enums to superset enums.</p>



<a name="210615574"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210615574" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jake Goulding <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210615574">(Sep 19 2020 at 13:36)</a>:</h4>
<blockquote>
<p>It would be nice if you could specify that a function returns only a subset of an enum</p>
</blockquote>
<p>As stated, that requires a language change. I'm seeking to achieve that goal by making creating the errors, enums, and conversions easier.</p>



<a name="210615628"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210615628" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jake Goulding <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210615628">(Sep 19 2020 at 13:36)</a>:</h4>
<p>However, think of a library where every function returns a unique error type. I think you'd hate it.</p>



<a name="210615642"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210615642" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Joshua Nelson <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210615642">(Sep 19 2020 at 13:36)</a>:</h4>
<p><span class="user-mention silent" data-user-id="116155">Jake Goulding</span> <a href="#narrow/stream/257204-project-error-handling/topic/Better.20enums/near/210615628">said</a>:</p>
<blockquote>
<p>However, think of a library where every function returns a unique error type. I think you'd hate it.</p>
</blockquote>
<p>you'd <em>have</em> to use an error handling library that has a single error type</p>



<a name="210615658"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210615658" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Joshua Nelson <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210615658">(Sep 19 2020 at 13:37)</a>:</h4>
<p>(or <code>Box&lt;dyn Error&gt;</code> everywhere)</p>



<a name="210618051"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210618051" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Seán Kelleher <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210618051">(Sep 19 2020 at 14:32)</a>:</h4>
<p><span class="user-mention silent" data-user-id="116155">Jake Goulding</span> <a href="#narrow/stream/257204-project-error-handling/topic/Better.20enums/near/210615628">said</a>:</p>
<blockquote>
<p>However, think of a library where every function returns a unique error type. I think you'd hate it.</p>
</blockquote>
<p>This actually sounds appealing to me, and from my brief experience Rust seems to allow consuming such libraries with low overhead. Do you have more thoughts on why it would be undesirable? Perhaps because it'd be difficult/impossible to write catch-all handler functions?</p>



<a name="210619074"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210619074" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jake Goulding <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210619074">(Sep 19 2020 at 14:54)</a>:</h4>
<p>As soon as you call two functions with different error types and want to return either, you need to unify them somehow. That means either boxing them or creating a new type (usually an enum). SNAFU is all about creating those enums easier, but it’s still an amount of work you have to do.</p>



<a name="210619082"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210619082" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jake Goulding <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210619082">(Sep 19 2020 at 14:54)</a>:</h4>
<p>So I guess my objection is that it’s not actually low overhead.</p>



<a name="210619287"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210619287" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jake Goulding <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210619287">(Sep 19 2020 at 14:58)</a>:</h4>
<p>Even with a language-based solution, you’d still have to type all the specific variants in the signature (and then have all the downsides of a unnameable type)</p>



<a name="210619556"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210619556" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jake Goulding <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210619556">(Sep 19 2020 at 15:05)</a>:</h4>
<p>There’s also a decision about who takes on the overhead. If the library does it, then every user can benefit at the risk of it not being a perfect fit. If the library punts on it, then every user has to re-create similar work</p>



<a name="210619914"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210619914" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> oliver <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210619914">(Sep 19 2020 at 15:13)</a>:</h4>
<p>For you what are the downsides of unnameable types?</p>



<a name="210620563"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210620563" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jake Goulding <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210620563">(Sep 19 2020 at 15:29)</a>:</h4>
<p>That you can’t name it :-)</p>
<p>You can’t document it, You can’t reuse them without introducing duplication.</p>



<a name="210620843"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210620843" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> oliver <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210620843">(Sep 19 2020 at 15:35)</a>:</h4>
<p>tl;dr is it a undocumented feature or a side effect of the type system?</p>



<a name="210620980"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210620980" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> oliver <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210620980">(Sep 19 2020 at 15:38)</a>:</h4>
<p>there just doesn't seem to be a whole lot of attention given to it overall</p>



<a name="210621326"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210621326" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jake Goulding <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210621326">(Sep 19 2020 at 15:44)</a>:</h4>
<p>I’m not sure exactly what you are referring to. Right now there’s no language feature for anonymous enums, which is what I think the initial intent was. </p>
<p>There are anonymous types around traits, which is mostly what I’m basing the downsides around.</p>



<a name="210621691"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210621691" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> oliver <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210621691">(Sep 19 2020 at 15:54)</a>:</h4>
<p>From what I can gather at a glance unnameable types are a problem which work has gone into to mitigate and anonymous enums are a proposed feature</p>



<a name="210622212"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210622212" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> oliver <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210622212">(Sep 19 2020 at 16:07)</a>:</h4>
<p>This might also be related to opaque types?</p>



<a name="210626321"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210626321" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Charles Lew <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210626321">(Sep 19 2020 at 17:42)</a>:</h4>
<p>I feel that, it's not that useful to <code>enum</code> all kinds of errors. It would be more useful if we can classify error into how we want to deal with them. Basically there's three strategies: Abort,  Retry, Ignore. If you already decided to abort, what caused it is not at all very useful... It's in what situations you should retry or ignore is very useful.</p>



<a name="210627361"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210627361" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jake Goulding <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210627361">(Sep 19 2020 at 18:08)</a>:</h4>
<p><span class="user-mention silent" data-user-id="281739">oliver</span> <a href="#narrow/stream/257204-project-error-handling/topic/Better.20enums/near/210621691">said</a>:</p>
<blockquote>
<p>From what I can gather at a glance unnameable types are a problem which work has gone into to mitigate and anonymous enums are a proposed feature</p>
</blockquote>
<p>Maybe? Rust 1.0 had unnamable types (every closure), then Rust 1.26 added <code>impl Trait</code> syntax to allow semi-naming them, at least their shape. Work continues on to make these more useful.</p>



<a name="210627398"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210627398" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jake Goulding <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210627398">(Sep 19 2020 at 18:09)</a>:</h4>
<p><span class="user-mention silent" data-user-id="116458">Charles Lew</span> <a href="#narrow/stream/257204-project-error-handling/topic/Better.20enums/near/210626321">said</a>:</p>
<blockquote>
<p>I feel that, it's not that useful to <code>enum</code> all kinds of errors. It would be more useful if we can classify error into how we want to deal with them. </p>
</blockquote>
<p>This assumes that there's a single such grouping. What categorization is "failing to open a file"?</p>



<a name="210627645"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210627645" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Markus Unterwaditzer <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210627645">(Sep 19 2020 at 18:15)</a>:</h4>
<p><span class="user-mention silent" data-user-id="116155">Jake Goulding</span> <a href="#narrow/stream/257204-project-error-handling/topic/Better.20enums/near/210615628">said</a>:</p>
<blockquote>
<p>However, think of a library where every function returns a unique error type. I think you'd hate it.</p>
</blockquote>
<p>you could possibly paper over the effects of this by doing something like this:</p>
<div class="codehilite"><pre><span></span><code><span class="c1">// in library</span>
<span class="cp">#[derive(From, Into)]</span><span class="w">   </span><span class="c1">// imagine this is from derive_more or w/e</span>
<span class="k">enum</span> <span class="nc">AllErrors</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="n">Error1</span><span class="p">(</span><span class="n">Error1</span><span class="p">),</span><span class="w"></span>
<span class="w">    </span><span class="n">Error2</span><span class="p">(</span><span class="n">Error2</span><span class="p">)</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>

<span class="c1">// in app</span>
<span class="k">enum</span> <span class="nc">AppError</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="n">LibraryError</span><span class="p">(</span><span class="n">AllErrors</span><span class="p">)</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>

<span class="k">impl</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="w"> </span><span class="nb">From</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">AppError</span><span class="w"> </span><span class="k">where</span><span class="w"> </span><span class="n">T</span>: <span class="nb">Into</span><span class="o">&lt;</span><span class="n">AllErrors</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="k">fn</span> <span class="nf">from</span><span class="p">(</span><span class="n">e</span>: <span class="nc">T</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">AppError</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="n">AppError</span>::<span class="n">LibraryError</span><span class="p">(</span><span class="n">e</span><span class="p">.</span><span class="n">into</span><span class="p">())</span><span class="w"></span>
<span class="w">    </span><span class="p">}</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>


<p>unfortunately this would instantly conflict with other trait impls, such as <code>Impl Into&lt;AllErrors&gt; for AppError</code>... need specialization again? or perhaps the library exports a macro that explicitly impls From for all its errors for a given type.</p>



<a name="210628701"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210628701" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> oliver <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210628701">(Sep 19 2020 at 18:35)</a>:</h4>
<p><span class="user-mention silent" data-user-id="116458">Charles Lew</span> <a href="#narrow/stream/257204-project-error-handling/topic/Better.20enums/near/210626321">said</a>:</p>
<blockquote>
<p>It would be more useful if we can classify error into how we want to deal with them.</p>
</blockquote>
<p>Some errors may also result in UB where others do not.</p>



<a name="210628931"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210628931" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jake Goulding <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210628931">(Sep 19 2020 at 18:40)</a>:</h4>
<p><span class="user-mention" data-user-id="344315">@Markus Unterwaditzer</span> I think that would run into <a href="https://stackoverflow.com/q/37347311/155423">https://stackoverflow.com/q/37347311/155423</a> quickly. However, the enum that you've described is more-or-less exactly what SNAFU does. With current syntax:</p>
<div class="codehilite"><pre><span></span><code><span class="cp">#[derive(Debug, Snafu)]</span><span class="w"></span>
<span class="k">enum</span> <span class="nc">AllErrors</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="n">Error1</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">source</span>: <span class="nc">Error1</span><span class="w"> </span><span class="p">},</span><span class="w"></span>
<span class="w">    </span><span class="n">Error2</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">source</span>: <span class="nc">Error2</span><span class="w"> </span><span class="p">},</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>



<a name="210628994"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210628994" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jake Goulding <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210628994">(Sep 19 2020 at 18:41)</a>:</h4>
<p><span class="user-mention silent" data-user-id="281739">oliver</span> <a href="#narrow/stream/257204-project-error-handling/topic/Better.20enums/near/210628701">said</a>:</p>
<blockquote>
<p>Some errors may also result in UB where others do not.</p>
</blockquote>
<p>That sounds (a) interesting (b) hard-to-believe and (c) like a separate topic. Perhaps you'd care to start a new topic describing how that could happen?</p>



<a name="210629070"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210629070" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> oliver <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210629070">(Sep 19 2020 at 18:42)</a>:</h4>
<p>Not especially if it isn't toally germane to the current discussion</p>



<a name="210635297"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210635297" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> isHavvy <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210635297">(Sep 19 2020 at 21:05)</a>:</h4>
<p><span class="user-mention silent" data-user-id="116155">Jake Goulding</span> <a href="#narrow/stream/257204-project-error-handling/topic/Better.20enums/near/210615628">said</a>:</p>
<blockquote>
<p>However, think of a library where every function returns a unique error type. I think you'd hate it.</p>
</blockquote>
<p>Is that any worse than each <code>Iterator</code> function returning its own iterator type?</p>



<a name="210635976"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210635976" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jake Goulding <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210635976">(Sep 19 2020 at 21:22)</a>:</h4>
<p>It certainly feels different. Other than itertools, I don’t know of a library where every function returns an iterator. 😅</p>



<a name="210636001"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210636001" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jake Goulding <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210636001">(Sep 19 2020 at 21:23)</a>:</h4>
<p>There’s also a matter of composition. Iterators tend to compose with less hassle.</p>



<a name="210636057"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210636057" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jake Goulding <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210636057">(Sep 19 2020 at 21:24)</a>:</h4>
<p>Although I think improving error-bearing iterators could also be something the project looks at and potentially improves</p>



<a name="210636061"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210636061" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jake Goulding <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210636061">(Sep 19 2020 at 21:25)</a>:</h4>
<p>Although a different topic as well.</p>



<a name="210636319"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210636319" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jake Goulding <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210636319">(Sep 19 2020 at 21:30)</a>:</h4>
<p><span class="user-mention" data-user-id="240091">@alex</span> circling back to your original point, <strong>why</strong> do <em>you</em> wish for such a feature? You gave a potential implementation, but glossed over the benefit you are seeking.</p>



<a name="210637731"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210637731" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jake Goulding <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210637731">(Sep 19 2020 at 22:11)</a>:</h4>
<blockquote>
<p>Iterators tend to compose with less hassle.</p>
</blockquote>
<p>You can get easy composition of errors by boxing them always, but then you lose the ability to easily test for a specific error. </p>
<p>Iterators also tend to wrap their underlying iterator via generics. That’s something that errors could do (and SNAFU supports it) but it’s pretty unusual.</p>



<a name="210637781"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210637781" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jake Goulding <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210637781">(Sep 19 2020 at 22:12)</a>:</h4>
<p><code>fn foo() -&gt; Result&lt;(), impl Error&gt;</code> would likewise be surprising.</p>



<a name="210637900"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210637900" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> BatmanAoD (Kyle Strand) <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210637900">(Sep 19 2020 at 22:16)</a>:</h4>
<p>I'm a bit confused about the composition-without-boxing issue. Isn't that trivial? <code>?</code> automatically calls <code>into()</code> if necessary, and the conversion from one enum into a "superset" enum should be very simple (in fact it could even be a no-op in most cases).</p>



<a name="210638104"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210638104" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> simulacrum <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210638104">(Sep 19 2020 at 22:22)</a>:</h4>
<p><span class="user-mention" data-user-id="120076">@BatmanAoD (Kyle Strand)</span> I think the point is that the superset enum doesn't exist unless the library provides it</p>



<a name="210638113"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210638113" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> simulacrum <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210638113">(Sep 19 2020 at 22:22)</a>:</h4>
<p>and if you do this "right" you then presumably need <em>tons</em> of such enums</p>



<a name="210638119"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210638119" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> simulacrum <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210638119">(Sep 19 2020 at 22:22)</a>:</h4>
<p>for every pair/three/... distinct small error enums/structs in your library</p>



<a name="210638139"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210638139" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> simulacrum <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210638139">(Sep 19 2020 at 22:23)</a>:</h4>
<p>and at that point you really just want language support. One thing I've thought about historically is that if we had "enum from impl Trait" or similar, we could do something like <code>Result&lt;(), impl Any + Error&gt;</code>, but it's ... not perfect, perhaps</p>



<a name="210638183"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210638183" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> simulacrum <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210638183">(Sep 19 2020 at 22:24)</a>:</h4>
<p>though I guess error already supports downcasting, so you don't need the Any</p>



<a name="210638190"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210638190" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> BatmanAoD (Kyle Strand) <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210638190">(Sep 19 2020 at 22:24)</a>:</h4>
<p>Right, but that's a different problem than composability, I think. But yes, that's a ton of code.</p>



<a name="210638216"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210638216" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> simulacrum <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210638216">(Sep 19 2020 at 22:25)</a>:</h4>
<p>I think the problem is that easily composable errors lead you to big error enums (or erased errors), both of which mean that you can't easily know "okay, I've handled all cases that this function can return"</p>



<a name="210638265"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210638265" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> simulacrum <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210638265">(Sep 19 2020 at 22:26)</a>:</h4>
<p>kind of like how e.g. std::io::copy between two vectors basically can't fail, but the compiler can't catch it for you today because it just returns io::Result</p>



<a name="210638269"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210638269" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jake Goulding <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210638269">(Sep 19 2020 at 22:26)</a>:</h4>
<p>Pedantically, it calls <code>into</code> unconditionally <span aria-label="innocent" class="emoji emoji-1f607" role="img" title="innocent">:innocent:</span></p>
<p>The non-trivial point I see is the creation of those enums. The language doesn’t create them for you. SNAFU can help, but people seem to prefer the boxing path, presumably because of the simplicity of use. </p>
<p>How do you see those enums being defined / created? An interesting exercise would be 3 leaf errors and then all 6 permutations of those errors (half demonstrated above)</p>



<a name="210638288"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210638288" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jake Goulding <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210638288">(Sep 19 2020 at 22:27)</a>:</h4>
<p>Or <span class="user-mention" data-user-id="116122">@simulacrum</span> could say the same thing but better while I’m typing. 😴</p>



<a name="210638359"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210638359" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> simulacrum <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210638359">(Sep 19 2020 at 22:28)</a>:</h4>
<p>It's certainly an interesting (and hard!) problem to solve. fine-grained composability, especially with semver-promises, seems both fragile and perhaps too similar to checked exceptions from Java to my liking... but it may also be not that bad, if you can have the compiler take care of it for you. I think my major complaint with checked exceptions in Java was always repeating myself in the callstack</p>



<a name="210640707"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210640707" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jason Smith <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210640707">(Sep 19 2020 at 23:41)</a>:</h4>
<p>The use pattern for errors is that you generally care about one or two types and you pass the rest to the default handler (up the stack). I've seen entire libraries written to throw Exception (a general type of error) in Java because there are just too many exception cases propagating around. This is similar to the Anyhow solution, which might not be ideal, but it gets the job done without loss of sanity. :) It seems like there should be something better in a language known for its strong typing, though.</p>



<a name="210644027"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210644027" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jane Lusby <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210644027">(Sep 20 2020 at 01:37)</a>:</h4>
<p><span class="user-mention" data-user-id="116122">@simulacrum</span> for the repeating bit do you mean writing errors out in the signature of leaf functions and then having to write those errors in every function that calls those?</p>



<a name="210644064"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210644064" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> simulacrum <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210644064">(Sep 20 2020 at 01:38)</a>:</h4>
<p>Yep, though I don't know of a good solution</p>



<a name="210644065"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210644065" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jane Lusby <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210644065">(Sep 20 2020 at 01:38)</a>:</h4>
<p>I'm not super familiar with checked exceptions</p>



<a name="210644068"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210644068" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jane Lusby <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210644068">(Sep 20 2020 at 01:38)</a>:</h4>
<p>I'm wondering if somehow associated types could help with this</p>



<a name="210644072"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210644072" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jane Lusby <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210644072">(Sep 20 2020 at 01:38)</a>:</h4>
<p>like if you could create an associated error type for a function</p>



<a name="210644077"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210644077" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jane Lusby <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210644077">(Sep 20 2020 at 01:38)</a>:</h4>
<p>then use an anon enum to define it, and then you could name that associated type</p>



<a name="210644087"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210644087" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jane Lusby <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210644087">(Sep 20 2020 at 01:39)</a>:</h4>
<p>I feel like unioning the different error types would still be an issue tho</p>



<a name="210644134"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210644134" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> simulacrum <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210644134">(Sep 20 2020 at 01:40)</a>:</h4>
<p>Hm, perhaps. I think the challenge is that you probably want semver guarantees for the list (at least that it won't grow, shrinking seems fine), but to do that well you really do want to enumerate the list, at least in public functions</p>



<a name="210644147"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210644147" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> simulacrum <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210644147">(Sep 20 2020 at 01:42)</a>:</h4>
<p>But I personally haven't written ~any Rust libraries with error types, so maybe this is not too much of a problem in practice. Certainly I can't think of cases where I sort of wanted this</p>



<a name="210644186"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210644186" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> simulacrum <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210644186">(Sep 20 2020 at 01:42)</a>:</h4>
<p>(I guess for e.g. serde it would be cool to have infallible serialization, but that seems hard and not worth it)</p>



<a name="210644231"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210644231" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> simulacrum <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210644231">(Sep 20 2020 at 01:44)</a>:</h4>
<p>I think most of the time when I've felt an API returning a smaller set would be good, that wouldn't be practical because the API is a trait or equivalent to that, and so having the error type be more specific isn't practical</p>



<a name="210644763"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210644763" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Charles Lew <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210644763">(Sep 20 2020 at 02:03)</a>:</h4>
<p><span class="user-mention silent" data-user-id="116155">Jake Goulding</span> <a href="#narrow/stream/257204-project-error-handling/topic/Better.20enums/near/210627398">said</a>:</p>
<blockquote>
<p><span class="user-mention silent" data-user-id="116458">Charles Lew</span> <a href="#narrow/stream/257204-project-error-handling/topic/Better.20enums/near/210626321">said</a>:<br>
This assumes that there's a single such grouping. What categorization is "failing to open a file"?</p>
</blockquote>
<p>I think callee define all kinds of errors, and caller define the categorization.</p>



<a name="210652241"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210652241" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> XAMPPRocky <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210652241">(Sep 20 2020 at 06:29)</a>:</h4>
<p><span class="user-mention" data-user-id="116122">@simulacrum</span> Slightly off topic but serde does have infallible serialisation since the error type is an associated type of Serializer. So you could just use a unit struct for that particular case.</p>



<a name="210653759"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210653759" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> isHavvy <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210653759">(Sep 20 2020 at 07:18)</a>:</h4>
<p>Straw man syntax:</p>
<div class="codehilite"><pre><span></span><code><span class="k">enum</span> <span class="nc">LibraryError</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="n">E1</span><span class="p">,</span><span class="w"> </span><span class="n">E2</span><span class="p">,</span><span class="w"> </span><span class="n">E3</span><span class="p">,</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>

<span class="k">fn</span> <span class="nf">foo</span><span class="p">()</span><span class="w"> </span>-&gt; <span class="nb">Result</span><span class="o">&lt;</span><span class="p">(),</span><span class="w"> </span><span class="n">FooError</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nb">Err</span><span class="p">(</span><span class="n">LibraryError</span>::<span class="n">E3</span><span class="p">)</span><span class="w"> </span><span class="p">}</span><span class="w"></span>

<span class="n">subenum</span><span class="w"> </span><span class="n">FooError</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">LibraryError</span>::<span class="p">{</span><span class="n">E2</span><span class="p">,</span><span class="w"> </span><span class="n">E3</span><span class="p">};</span><span class="w"></span>
</code></pre></div>



<a name="210653924"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210653924" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> isHavvy <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210653924">(Sep 20 2020 at 07:25)</a>:</h4>
<p>We would extend <code>as</code> to allow casting from a subenum to its parent enum (or parent subenum should we allow subenums of subenums)</p>



<a name="210654186"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210654186" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Lokathor <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210654186">(Sep 20 2020 at 07:33)</a>:</h4>
<p>subenum should probably just auto-coerce into the parent type as necessary.</p>



<a name="210654355"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210654355" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> isHavvy <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210654355">(Sep 20 2020 at 07:38)</a>:</h4>
<p>That can work. The main thing I think that should stand out about one is that you can match over <code>FooError</code> and not have to worry about <code>LibraryError::E1</code>. Could even possibly allow associated items on <code>FooError</code>.</p>



<a name="210658659"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210658659" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Seán Kelleher <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210658659">(Sep 20 2020 at 09:53)</a>:</h4>
<p>I'd like to submit the approach that I've been using briefly, but have been contemplating for a while. For reference, a lot of this approach can be seen in the first commit for a small new <a href="https://github.com/eZanmoto/dpnd/blob/master/src/main.rs">project</a> I'm working on.</p>
<p>I currently prefer the approach of simply having a unique error enum for each function that describes the all the different failures that that function can generate. This has the negative of being more work for the function author, but has the most flexibility in my opinion.</p>
<p>An example is the "leaf" method <code>parse_deps</code>, which can return a <code>ParseDepsError</code>, defined as follows:</p>
<div class="codehilite"><pre><span></span><code>enum ParseDepsError {
    DupDepName(usize, String, usize),
    InvalidDepName(usize, String, usize),
    InvalidDepSpec(usize, String),
    UnknownTool(usize, String, String),
}
</code></pre></div>


<p>(For this, I think that record syntax would provide much better readibility and I intend to refactor <code>ParseDepsError</code> to use it; I'll leave this aspect of the discussion to the side for now.)</p>
<p>In terms of composability, I think that the best approach is for consuming functions to simply nest inner errors in their own error enums. For example, <code>parse_deps</code> is called by <code>parse_deps_conf</code>, which has the following error enum:</p>
<div class="codehilite"><pre><span></span><code>enum ParseDepsConfError {
    MissingOutputDir,
    ParseDepsFailed(ParseDepsError),
}
</code></pre></div>


<p>It adds its own extra failure condition, but in the case of a sub-failure, it simply tags it and nests it. A handler then has the choice of drilling into the error to get more information, if they want.</p>
<p>To cater for slightly easier error-handling I also have a <code>wrap_err!</code> macro, similar in nature to <code>try!</code>:</p>
<div class="codehilite"><pre><span></span><code>macro_rules! wrap_err {
    ($x:expr, $y:path $(, $z:expr)* $(,)?) =&gt; {{
        match $x {
            Ok(v) =&gt; {
                v
            },
            Err(e) =&gt; {
                return Err($y(e $(, $z)*));
            },
        }
    }}
}
</code></pre></div>


<p>I'll give an example usage. <code>install</code> can return an <code>InstallError</code>, and one of its possible values is <code>CreateMainOutputDirFailed(IoError, PathBuf)</code>. This allows for the following call:</p>
<div class="codehilite"><pre><span></span><code>wrap_err!(
    fs::create_dir_all(&amp;conf.output_dir),
    InstallError::CreateMainOutputDirFailed,
    conf.output_dir,
);
</code></pre></div>


<p>This, like <code>try!</code>, returns the <code>Ok</code> value of the call on success. On <code>Err(err)</code>, however, the function will return <code>CreateMainOutputDirFailed(err, conf.output_dir)</code>, which nests the error and adds some contextual information, for both logical and debugging purposes. From my understanding, "wrapping" the error in such a way is trickier with <code>try!</code> because of the following:</p>
<ul>
<li><code>impl From&lt;io::Error&gt; for MyError</code> must be implemented for each wrapped error type, and you can't distinguish between different <code>io::Error</code>s.</li>
<li>You can't add contextual information.</li>
</ul>
<p>The big caveat of <code>wrap_err!</code>, in my opinion, is its blockiness. My personal code style has some accountability here, but looking at the definition of <a href="https://github.com/eZanmoto/dpnd/blob/master/src/main.rs#L39"><code>install</code></a>, you can probably see how <code>wrap_err</code> obscures the "happy path" logic somewhat. I think this could probably be remedied somewhat by adding <code>wrap_err!</code> support to <code>Result</code>, so that the following could be done:</p>
<div class="codehilite"><pre><span></span><code>fs::create_dir_all(&amp;conf.output_dir)
    .wrap_err!(
        InstallError::CreateMainOutputDirFailed,
        conf.output_dir,
    );
</code></pre></div>


<p>But that's more of a personal improvement idea, rather than a suggestion.</p>
<p>One benefit of the above approach, in my opinion, is to be able to define a comprehensive error handler at the top level which can give very specific error messages. Even better, in my opinion, is that the error messages themselves are defined at the top level, where they belong, as opposed to in the generating functions, as you might find in say, Go error handling, for example. Again, it might not be to everyone's liking, but <a href="https://github.com/eZanmoto/dpnd/blob/master/src/main.rs#L261">here</a> is the top-level error handling routine that I mention. Note also that such a routine is much more amenable to say, localisation, and other processing, in my opinion.</p>
<p>Sorry for the wall of text; like I mentioned, these are ideas that have been germinating for a while and I'm excited to suggest. Let me know what you think!  Thanks.</p>



<a name="210658704"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210658704" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Seán Kelleher <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210658704">(Sep 20 2020 at 09:54)</a>:</h4>
<p>As a side note, I also adopted the following convention in the above project:</p>
<blockquote>
<p>This project also identifies two types of error value. An error that contains a nested error is considered a "failed operation" error. Such error values should end with <code>Failed</code> and the nested error(s) should be the first listed in the associated tuple data. For example:</p>
<div class="codehilite"><pre><span></span><code>enum InstallError&lt;E&gt; {
    GetCurrentDirFailed(IoError),
    ...
}
</code></pre></div>


<p>Any other error is considered a "root" error, and has no required naming or data conventions. For example:</p>
<div class="codehilite"><pre><span></span><code>enum InstallError&lt;E&gt; {
    ...
    NoDepsFileFound,
    ...
}

enum ParseDepsError {
    InvalidDependencySpec(usize, String),
    UnknownTool(usize, String, String),
}
</code></pre></div>


</blockquote>



<a name="210661322"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210661322" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jane Lusby <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210661322">(Sep 20 2020 at 11:04)</a>:</h4>
<p>hi <span class="user-mention" data-user-id="344273">@Seán Kelleher</span>, some thoughts on your suggestions:</p>
<p>the wrap_err function you suggested sounds a lot like map_err, is there a reason you didn't use that? alternatively it's very similar to the context function on SNAFU.</p>
<p>regarding the print_install_error, is there a reason you didn't implement the error trait and use that to print your errors? I have a great deal of interest in this specific problem myself and wonder what you think of error reporting crates like eyre and anyhow that are built ontop of the error trait and why you choose to implement a manual printing method specific to your error type rather than using error trait based composition to print your errors generically.</p>



<a name="210662159"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210662159" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jake Goulding <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210662159">(Sep 20 2020 at 11:23)</a>:</h4>
<p><span class="user-mention" data-user-id="344273">@Seán Kelleher</span> yes, it sounds like you have 90-95% overlap with the goals and current implementation of  SNAFU</p>



<a name="210662182"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210662182" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jake Goulding <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210662182">(Sep 20 2020 at 11:24)</a>:</h4>
<div class="codehilite"><pre><span></span><code><span class="n">fs</span>::<span class="n">create_dir_all</span><span class="p">(</span><span class="o">&amp;</span><span class="n">conf</span><span class="p">.</span><span class="n">output_dir</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="p">.</span><span class="n">context</span><span class="p">(</span><span class="n">CreateMainOutputDirFailed</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">dir</span>: <span class="nc">conf</span><span class="p">.</span><span class="n">output_dir</span><span class="w"> </span><span class="p">})</span><span class="o">?</span><span class="w"></span>
</code></pre></div>



<a name="210662246"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210662246" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jake Goulding <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210662246">(Sep 20 2020 at 11:25)</a>:</h4>
<div class="codehilite"><pre><span></span><code><span class="cp">#[derive(Debug, Snafu)]</span><span class="w"></span>
<span class="k">enum</span> <span class="nc">ParseDepsError</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="cp">#[snafu(display(</span><span class="s">&quot;This is the text {}, {}&quot;</span><span class="cp">, alpha, gamma))]</span><span class="w"></span>
<span class="w">    </span><span class="n">DupDepName</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">alpha</span>: <span class="kt">usize</span><span class="p">,</span><span class="w"> </span><span class="n">beta</span>: <span class="nb">String</span><span class="p">,</span><span class="w"> </span><span class="n">gamma</span>: <span class="kt">usize</span> <span class="p">},</span><span class="w"></span>
</code></pre></div>



<a name="210662334"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210662334" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jake Goulding <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210662334">(Sep 20 2020 at 11:27)</a>:</h4>
<blockquote>
<p>much more amenable to say, localisation</p>
</blockquote>
<p>Yep. My hope is to combine Fluent somehow <a href="https://github.com/projectfluent/fluent-rs/issues/107">https://github.com/projectfluent/fluent-rs/issues/107</a></p>



<a name="210662565"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210662565" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Seán Kelleher <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210662565">(Sep 20 2020 at 11:33)</a>:</h4>
<p>Hi Jane and Jake,</p>
<p>Thanks very much for the questions. For the most part, I must admit I don't have much familiarity with Rust, and so a lot of my approach is a halfway-house between my personal ideal and whatever tools make themselves apparent to me at the time. As such, I wasn't actually aware of <code>map_err</code>, but at a cursory glance the main difference I can see is that <code>wrap_err!</code> is able to <code>return</code> the resulting error, but with <code>map_err</code> that would need to be done in a following statement. Other than that I think <code>map_err</code> looks almost ideal, if it can be used like the following:</p>
<div class="codehilite"><pre><span></span><code>fs::create_dir_all(&amp;conf.output_dir)
    .map_err(|err| { InstallError::CreateMainOutputDirFailed(err, conf.output_dir) });
</code></pre></div>


<p>Looking at SNAFU, it looks like the context issue is handled quite nicely with it.</p>
<p>I'm not fully sure about your question about implementing the error trait, I might have to take a look at <code>eyre</code> and <code>anyhow</code> to compare the approaches; it could very well be that they achieve the same thing. If it's in terms of having the error be able to describe itself, I think that's useful to have, but I think that it's ultimately the application should render errors to the user manually, and relying on error's own descriptions can present errors in terms that are too low-level; this would be how things work in Go anyway, which is my primary language. Sorry if I've misunderstood though.</p>



<a name="210662620"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210662620" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Seán Kelleher <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210662620">(Sep 20 2020 at 11:34)</a>:</h4>
<p><span class="user-mention silent" data-user-id="116155">Jake Goulding</span> <a href="#narrow/stream/257204-project-error-handling/topic/Better.20enums/near/210662182">said</a>:</p>
<blockquote>
<div class="codehilite"><pre><span></span><code><span class="n">fs</span>::<span class="n">create_dir_all</span><span class="p">(</span><span class="o">&amp;</span><span class="n">conf</span><span class="p">.</span><span class="n">output_dir</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="p">.</span><span class="n">context</span><span class="p">(</span><span class="n">CreateMainOutputDirFailed</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">dir</span>: <span class="nc">conf</span><span class="p">.</span><span class="n">output_dir</span><span class="w"> </span><span class="p">})</span><span class="o">?</span><span class="w"></span>
</code></pre></div>


</blockquote>
<p>I actually haven't looked into SNAFU yet, but this looks ideal.</p>



<a name="210662703"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210662703" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Seán Kelleher <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210662703">(Sep 20 2020 at 11:36)</a>:</h4>
<p>Ah, I just realised that <code>map_err</code> can/should be used with <code>?</code> (I only checked the docs for usage); that actually works better than <code>wrap_err</code> in that case so.</p>



<a name="210663068"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210663068" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jake Goulding <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210663068">(Sep 20 2020 at 11:46)</a>:</h4>
<blockquote>
<p>but I think that it's ultimately the application should render errors to the user manually</p>
</blockquote>
<p>I think you'll ultimately find this to be difficult. For that to be fully realized, every error exposed by every library would have to give complete access to all the variants. This makes it much harder for a library to adhere to semver, and is probably downright impossible given platform-specific concerns.</p>



<a name="210663079"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210663079" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jake Goulding <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210663079">(Sep 20 2020 at 11:46)</a>:</h4>
<p>but within a specific crate, sure.</p>



<a name="210663146"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210663146" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jake Goulding <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210663146">(Sep 20 2020 at 11:48)</a>:</h4>
<blockquote>
<p>about implementing the error trait,</p>
</blockquote>
<p>Note that SNAFU also defines the Error trait for you.</p>



<a name="210663325"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210663325" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jane Lusby <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210663325">(Sep 20 2020 at 11:52)</a>:</h4>
<p>the way it normally works is you describe your errors with the error trait and then you define how to display them with a reporter</p>



<a name="210663334"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210663334" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jane Lusby <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210663334">(Sep 20 2020 at 11:53)</a>:</h4>
<p>I actually did a whole talk on this if you want a nice primer</p>



<a name="210663337"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210663337" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jane Lusby <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210663337">(Sep 20 2020 at 11:53)</a>:</h4>
<p><a href="https://youtu.be/rAF8mLI0naQ">https://youtu.be/rAF8mLI0naQ</a></p>
<div class="youtube-video message_inline_image"><a data-id="rAF8mLI0naQ" href="https://youtu.be/rAF8mLI0naQ"><img src="https://i.ytimg.com/vi/rAF8mLI0naQ/default.jpg"></a></div>



<a name="210663343"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210663343" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jane Lusby <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210663343">(Sep 20 2020 at 11:53)</a>:</h4>
<p>I even mention how this relates to go error handling briefly</p>



<a name="210663382"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210663382" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jane Lusby <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210663382">(Sep 20 2020 at 11:54)</a>:</h4>
<p>tho admittedly I know very little about go</p>



<a name="210663411"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210663411" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jane Lusby <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210663411">(Sep 20 2020 at 11:55)</a>:</h4>
<p>this doesn't really help with localization, in that case it's up to the author of the crate to provide localization support rather than the author of the app</p>



<a name="210663431"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210663431" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jane Lusby <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210663431">(Sep 20 2020 at 11:55)</a>:</h4>
<p>but this means that there's much less duplicated work, you don't end up with every crate that depends on your crate having to reimplement localization and error messages</p>



<a name="210663488"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210663488" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Charles Ellis O&#x27;Riley Jr. <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210663488">(Sep 20 2020 at 11:56)</a>:</h4>
<p>Thanks for the primer Jane.</p>



<a name="210663493"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210663493" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jane Lusby <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210663493">(Sep 20 2020 at 11:56)</a>:</h4>
<p>it's all tradeoffs, tho I doubt many people would want to adopt an error handling style where they have to define the error messages for foreign error types</p>



<a name="210663497"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210663497" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jane Lusby <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210663497">(Sep 20 2020 at 11:56)</a>:</h4>
<p>people already hate how verbose it is to just implement Error Display and From manually</p>



<a name="210663499"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210663499" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jane Lusby <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210663499">(Sep 20 2020 at 11:56)</a>:</h4>
<p>and that's just for the local error types</p>



<a name="210664067"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210664067" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> DPC <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210664067">(Sep 20 2020 at 12:11)</a>:</h4>
<p>would be nice to have <code>#[derive(Error)]</code> some point in the future <span aria-label="stuck out tongue" class="emoji emoji-1f61b" role="img" title="stuck out tongue">:stuck_out_tongue:</span></p>



<a name="210664492"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210664492" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jake Goulding <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210664492">(Sep 20 2020 at 12:22)</a>:</h4>
<p><span class="user-mention silent" data-user-id="120823">DPC</span> <a href="#narrow/stream/257204-project-error-handling/topic/Better.20enums/near/210664067">said</a>:</p>
<blockquote>
<p>would be nice to have <code>#[derive(Error)]</code> some point in the future :P</p>
</blockquote>
<p>I doubt it, just because <code>Error: Display</code> and deriving <code>Display</code> isn't really a _thing_.</p>



<a name="210664611"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210664611" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> DPC <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210664611">(Sep 20 2020 at 12:25)</a>:</h4>
<p>i'm aware hence "some point in future" <span aria-label="stuck out tongue" class="emoji emoji-1f61b" role="img" title="stuck out tongue">:stuck_out_tongue:</span></p>



<a name="210665322"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210665322" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jake Goulding <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210665322">(Sep 20 2020 at 12:41)</a>:</h4>
<p><span class="user-mention silent" data-user-id="220273">Jane Lusby</span> <a href="#narrow/stream/257204-project-error-handling/topic/Better.20enums/near/210663325">said</a>:</p>
<blockquote>
<p>the way it normally works is you describe your errors with the error trait and then you define how to display them with a reporter</p>
</blockquote>
<p>I mildly object to "normally", unless you call <code>unwrap</code>/<code>expect</code>/<code>println</code> a "reporter". Perhaps that's how it should be though.</p>



<a name="210665395"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210665395" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jake Goulding <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210665395">(Sep 20 2020 at 12:43)</a>:</h4>
<p><span class="user-mention" data-user-id="344273">@Seán Kelleher</span> another point is that you can define Error and Display for your error types but still match on them to do whatever you want, like display them differently</p>



<a name="210665458"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210665458" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jake Goulding <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210665458">(Sep 20 2020 at 12:44)</a>:</h4>
<p>SNAFU provides simple automatic implementations of Display, so you can use those if you mostly want to ignore Display anyway</p>



<a name="210666579"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210666579" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Seán Kelleher <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210666579">(Sep 20 2020 at 13:11)</a>:</h4>
<p><span class="user-mention silent" data-user-id="116155">Jake Goulding</span> <a href="#narrow/stream/257204-project-error-handling/topic/Better.20enums/near/210663068">said</a>:</p>
<blockquote>
<blockquote>
<p>but I think that it's ultimately the application should render errors to the user manually</p>
</blockquote>
<p>I think you'll ultimately find this to be difficult. For that to be fully realized, every error exposed by every library would have to give complete access to all the variants. This makes it much harder for a library to adhere to semver, and is probably downright impossible given platform-specific concerns.</p>
</blockquote>
<p>It's a good point in terms of practicality, and perhaps it's just a pipe dream. However, in terms of semver, I'm not fully sure how this could be addressed without having each function return <code>Error</code>. For example, I would expect that the idea of specifying subsets of <code>Error</code> for specific functions runs into the same issues with semver.</p>



<a name="210666592"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210666592" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Seán Kelleher <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210666592">(Sep 20 2020 at 13:11)</a>:</h4>
<p><span class="user-mention silent" data-user-id="220273">Jane Lusby</span> <a href="#narrow/stream/257204-project-error-handling/topic/Better.20enums/near/210663334">said</a>:</p>
<blockquote>
<p>I actually did a whole talk on this if you want a nice primer</p>
</blockquote>
<p>That's great, thanks for linking, I'll take a look at this later.</p>



<a name="210666789"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210666789" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Seán Kelleher <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210666789">(Sep 20 2020 at 13:16)</a>:</h4>
<p><span class="user-mention silent" data-user-id="220273">Jane Lusby</span> <a href="#narrow/stream/257204-project-error-handling/topic/Better.20enums/near/210663493">said</a>:</p>
<blockquote>
<p>it's all tradeoffs, tho I doubt many people would want to adopt an error handling style where they have to define the error messages for foreign error types</p>
</blockquote>
<p>I suppose this is the crux of the matter, and I would admit that my approach is a theoretical purist one (at least in my opinion), and wouldn't necessarily suit everyone's tastes. Thankfully, the different options I've seen so far seem fairly orthogonal, and I'm very happy with what I've been able to get with Rust out of the box.</p>



<a name="210670252"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210670252" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jake Goulding <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210670252">(Sep 20 2020 at 14:54)</a>:</h4>
<p><span class="user-mention silent" data-user-id="344273">Seán Kelleher</span> <a href="#narrow/stream/257204-project-error-handling/topic/Better.20enums/near/210666579">said</a>:</p>
<blockquote>
<p>I'm not fully sure how this could be addressed without having each function return <code>Error</code>. For example, I would expect that the idea of specifying subsets of <code>Error</code> for specific functions runs into the same issues with semver.</p>
</blockquote>
<p>The general problem is that a public enum has public variants with public fields. That means that removing variants or fields is a semver break. If you haven't used <code>#[nonexhaustive]</code>, then adding variants or fields is likewise a semver break. I'd expect any equivalent "anonymous enum" idea would have the same problem.</p>
<p>This ultimately means that things that should be innocuous refactorings because semver breaks. For example, if I had code like:</p>
<div class="codehilite"><pre><span></span><code><span class="k">pub</span><span class="w"> </span><span class="k">enum</span> <span class="nc">Error</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="n">NotFound</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">source</span>: <span class="nc">regex</span>::<span class="n">Error</span><span class="w"> </span><span class="p">},</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>


<p>but then realized I could replace the regex with a <code>str::starts_with</code>, I can't remove the error without a semver break. If that was my only usage of the regex crate, I can't even remove the (theoretically internal) dependency for the same reason.</p>



<a name="210670265"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210670265" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jake Goulding <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210670265">(Sep 20 2020 at 14:55)</a>:</h4>
<p>In SNAFU, I encourage people to have two layers — public opaque error types and internal fully-detailed error types.</p>



<a name="210670319"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210670319" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jake Goulding <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210670319">(Sep 20 2020 at 14:56)</a>:</h4>
<p>That way a crate exposes just <code>mycrate::Error</code> (or a small number of similar) that the author has to very carefully decide what to make public API.</p>



<a name="210671959"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210671959" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> oliver <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210671959">(Sep 20 2020 at 15:41)</a>:</h4>
<p><span class="user-mention silent" data-user-id="344273">Seán Kelleher</span> <a href="#narrow/stream/257204-project-error-handling/topic/Better.20enums/near/210666789">said</a>:</p>
<blockquote>
<p>Thankfully, the different options I've seen so far seem fairly orthogonal...</p>
</blockquote>
<p>Meaning different as a positive? Or meant to imply parallels to your proposal?</p>



<a name="210672034"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210672034" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> oliver <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210672034">(Sep 20 2020 at 15:43)</a>:</h4>
<p>Which parts specifically?</p>



<a name="210672123"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210672123" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> oliver <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210672123">(Sep 20 2020 at 15:45)</a>:</h4>
<p>Is the parts about nesting enums not viable?</p>



<a name="210673777"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210673777" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Seán Kelleher <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210673777">(Sep 20 2020 at 16:26)</a>:</h4>
<p><span class="user-mention silent" data-user-id="116155">Jake Goulding</span> <a href="#narrow/stream/257204-project-error-handling/topic/Better.20enums/near/210665395">said</a>:</p>
<blockquote>
<p><span class="user-mention silent" data-user-id="344273">Seán Kelleher</span> another point is that you can define Error and Display for your error types but still match on them to do whatever you want, like display them differently</p>
</blockquote>
<p>That's the thing, and one of the very nice nice aspects of Rust, is that these are all orthogonal concerns, and Rust seems to handle them all very nicely. I suppose my main objective here is to present my own thoughts and approach, and how I would see errors being treated in an ideal world.</p>



<a name="210674238"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210674238" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Seán Kelleher <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210674238">(Sep 20 2020 at 16:39)</a>:</h4>
<p><span class="user-mention silent" data-user-id="116155">Jake Goulding</span> <a href="#narrow/stream/257204-project-error-handling/topic/Better.20enums/near/210670252">said</a>:</p>
<blockquote>
<p><span class="user-mention silent" data-user-id="344273">Seán Kelleher</span> <a href="#narrow/stream/257204-project-error-handling/topic/Better.20enums/near/210666579">said</a>:</p>
<blockquote>
<p>I'm not fully sure how this could be addressed without having each function return <code>Error</code>. For example, I would expect that the idea of specifying subsets of <code>Error</code> for specific functions runs into the same issues with semver.</p>
</blockquote>
<p>The general problem is that a public enum has public variants with public fields. That means that removing variants or fields is a semver break. If you haven't used <code>#[nonexhaustive]</code>, then adding variants or fields is likewise a semver break. I'd expect any equivalent "anonymous enum" idea would have the same problem.</p>
<p>This ultimately means that things that should be innocuous refactorings because semver breaks. For example, if I had code like:</p>
<div class="codehilite"><pre><span></span><code><span class="k">pub</span><span class="w"> </span><span class="k">enum</span> <span class="nc">Error</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="n">NotFound</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">source</span>: <span class="nc">regex</span>::<span class="n">Error</span><span class="w"> </span><span class="p">},</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>


<p>but then realized I could replace the regex with a <code>str::starts_with</code>, I can't remove the error without a semver break. If that was my only usage of the regex crate, I can't even remove the (theoretically internal) dependency for the same reason.</p>
</blockquote>
<p>Definitely, it's absolutely a tradeoff. Moreover, where semver usually allows, say, adding new enum values in the same major version, because of the Rust's exhaustive matching, this will also cause a break. I suppose it all boils down to compromise, either of theoretical ideals, or of practicality. For example, with the <code>Error::NotFound</code> example, you could still keep the enum value, even if it's not being used anymore, if you decide that it's more important to you not to do a version bump.</p>
<p>Note that I think the same issue exists with a "global-union"-type <code>Error</code>; if you do a refactoring where the <code>Error::NotFound</code> value just isn't returned anymore, you'll similarly be faced with the choice of a semver bump or unused value. The difference is in how often these issues are likely to occur (more often with function-specific errors, and less often with <code>Error</code>, probably).</p>



<a name="210674301"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210674301" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> oliver <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210674301">(Sep 20 2020 at 16:40)</a>:</h4>
<p><span class="user-mention silent" data-user-id="344273">Seán Kelleher</span> <a href="#narrow/stream/257204-project-error-handling/topic/Better.20enums/near/210673777">said</a>:</p>
<blockquote>
<p><span class="user-mention silent" data-user-id="116155">Jake Goulding</span> <a href="#narrow/stream/257204-project-error-handling/topic/Better.20enums/near/210665395">said</a>:</p>
<blockquote>
<p><span class="user-mention silent" data-user-id="344273">Seán Kelleher</span> another point is that you can define Error and Display for your error types but still match on them to do whatever you want, like display them differently</p>
</blockquote>
<p>That's the thing, and one of the very nice nice aspects of Rust, is that these are all orthogonal concerns, and Rust seems to handle them all very nicely. I suppose my main objective here is to present my own thoughts and approach, and how I would see errors being treated in an ideal world.</p>
</blockquote>
<p>I think I lost the thread of the discussion somewhere. You contributed some very<br>
interesting options and it was pointed out that <code>SNAFU</code> is similar in some of<br>
its designs. Is most everything related to <code>SNAFU</code> and your designs now to be<br>
considered untenable to the project goals? My tl;dr here of that is simply that<br>
it's generally too difficult to trace error logic manually with a sufficient<br>
level of specificity such that the concept of nested errors is out of scope.</p>



<a name="210674302"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210674302" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Seán Kelleher <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210674302">(Sep 20 2020 at 16:40)</a>:</h4>
<p><span class="user-mention silent" data-user-id="116155">Jake Goulding</span> <a href="#narrow/stream/257204-project-error-handling/topic/Better.20enums/near/210670319">said</a>:</p>
<blockquote>
<p>That way a crate exposes just <code>mycrate::Error</code> (or a small number of similar) that the author has to very carefully decide what to make public API.</p>
</blockquote>
<p>That's a very interesting approach; I'm not sure that I'd completely agree with it right now but it's definitely something I'm going to keep in mind as a possibility.</p>



<a name="210674373"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210674373" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Seán Kelleher <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210674373">(Sep 20 2020 at 16:43)</a>:</h4>
<p>Sorry <span class="user-mention" data-user-id="281739">@oliver</span> , I've been jumping around a bit throughout the day while I tried to answer on mobile, I'll try and address your comments now.</p>



<a name="210674761"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210674761" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jake Goulding <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210674761">(Sep 20 2020 at 16:53)</a>:</h4>
<blockquote>
<p>Note that I think the same issue exists with a "global-union"-type Error; if you do a refactoring where the Error::NotFound value just isn't returned anymore,</p>
</blockquote>
<p>Likewise, it's a semver-incompatible change to go from returning an error to not and vice-versa. At least going away from an error has an easy enough hack where you say <code>enum Error {}</code> and it becomes zero-sized.</p>



<a name="210674838"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210674838" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Seán Kelleher <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210674838">(Sep 20 2020 at 16:55)</a>:</h4>
<p><span class="user-mention silent" data-user-id="281739">oliver</span> <a href="#narrow/stream/257204-project-error-handling/topic/Better.20enums/near/210674301">said</a>:</p>
<blockquote>
<p>I think I lost the thread of the discussion somewhere. You contributed some very<br>
interesting options and it was pointed out that <code>SNAFU</code> is similar in some of<br>
its designs. Is most everything related to <code>SNAFU</code> and your designs now to be<br>
considered untenable to the project goals? My tl;dr here of that is simply that<br>
it's generally too difficult to trace error logic manually with a sufficient<br>
level of specificity such that the concept of nested errors is out of scope.</p>
</blockquote>
<p>From my understanding so far, it looks like most of what I want to be able to achieve with my own peculiar approach to error handling seems possible with <code>SNAFU</code>, even if I don't take some of the recommended approaches. The two main approaches that I don't see myself taking are to use <code>Error</code> types (I will endeavour to use function-level errors until I feel its infeasible), and to define rendering rules for error values on the error values themselves. However, due to the flexibility of Rust and <code>SNAFU</code>, it looks like I'm free to make those choices, with essentially no consequences. For example, I'm free to use nested errors in my projects as much as I want, and even if a crate exports errors with rendering rules specified on the error values, I believe it's feasible to ignore them and to specify a manual print function, if I so wish. This second point is greatly contrasted with the Go way of doing things, where you often depend on the error string returned from the lower level (unless the package authors are interested in exposing error values that can be handled properly).</p>
<p>On your TL;DR, this might be the case, but I suppose I'm just not yet convinced that it is too difficult. Of course, I'm not going to be pushing my approach on anyone, precisely because I don't have enough evidence to back it up.</p>



<a name="210674995"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210674995" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Seán Kelleher <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210674995">(Sep 20 2020 at 16:59)</a>:</h4>
<p><span class="user-mention silent" data-user-id="116155">Jake Goulding</span> <a href="#narrow/stream/257204-project-error-handling/topic/Better.20enums/near/210674761">said</a>:</p>
<blockquote>
<p>Likewise, it's a semver-incompatible change to go from returning an error to not and vice-versa. At least going away from an error has an easy enough hack where you say <code>enum Error {}</code> and it becomes zero-sized.</p>
</blockquote>
<p>That's very cool. As for <code>Error</code> vs function-errors in practical terms, for semver it probably boils down to the fact that you're likely going to encounter the same issues with both at some point, but the <code>Error</code> approach is likely to defer those issues for a lot longer. What do you think?</p>



<a name="210675382"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210675382" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> oliver <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210675382">(Sep 20 2020 at 17:08)</a>:</h4>
<p>Improving enums for multiple failure cases is specifically in-scope for the<br>
project. I'm not clear on exactly how simple that can or should be. What's<br>
exciting is the potential for something that really pushes the limits of some<br>
fundamental trade offs.</p>
<p>In terms of semvar, is it to mean that the change requires an edition update<br>
(i.e. it's a major breaking change)? Or is one just saying that packages<br>
adopting the (non-Rust-breaking) feature will then choose to break their own<br>
reverse dependencies?</p>



<a name="210675909"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/257204-project-error-handling/topic/Better%20enums/near/210675909" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jake Goulding <a href="https://rust-lang.github.io/zulip_archive/stream/257204-project-error-handling/topic/Better.20enums.html#210675909">(Sep 20 2020 at 17:22)</a>:</h4>
<p><span class="user-mention silent" data-user-id="281739">oliver</span> <a href="#narrow/stream/257204-project-error-handling/topic/Better.20enums/near/210675382">said</a>:</p>
<blockquote>
<p>Improving enums for multiple failure cases is specifically in-scope for the project.</p>
</blockquote>
<p>I suppose it depends on exactly what that means. I don't know for sure, but I didn't expect there to be any language-level changes from the group. At best it might identify some patterns or desires and then request / propose them to the lang team.</p>
<blockquote>
<p>What's exciting is the potential for something that really pushes the limits of some fundamental trade offs.</p>
</blockquote>
<p>One of the best parts of Rust, IMO.</p>
<blockquote>
<p>the change requires an edition update</p>
</blockquote>
<p>So long as you mean the generally-accepted "edition" (e.g. the 2015 and 2018 editions), then what I have described is not that. </p>
<blockquote>
<p>packages adopting the (non-Rust-breaking) feature will then choose to break their own reverse dependencies?</p>
</blockquote>
<p>The public API of a crate is subject to semver concerns. That a function returns a <code>Result</code> or not is part of the public API. The specific error type in a <code>Result</code> is part of the public API. Public fields of an error type are part of the public API. Enum variants and fields are part of the public API. Changing any of those (without very specific conditions) constitutes a semver-incompatible change to the crate and thus a new release with a semver-distinct version.</p>



<hr><p>Last updated: Aug 07 2021 at 22:04 UTC</p>
</html>